Passed
Push — master ( a8bdc8...2feb85 )
by
unknown
01:06
created

server.js ➔ ... ➔ ???   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 15
Bugs 2 Features 0
Metric Value
cc 3
c 15
b 2
f 0
nc 4
dl 0
loc 25
ccs 0
cts 14
cp 0
crap 12
rs 8.8571
nop 3
1
/**
2
 * Server main
3
 *
4
 * @since 1.0.0
5
 *
6
 */
7
8 4
const Hapi = require('hapi');
9
10 4
const vision = require('vision');
11 4
const inert = require('inert');
12 4
const HapiAuthJwt2 = require('hapi-auth-jwt2');
13 4
const HapiReactViews = require('hapi-react-views');
14 4
const HapiErrorHandler = require('./middleware/error-handler');
15 4
const HapiTransformer = require('./middleware/transformer');
16 4
const HapiAuthChecker = require('./middleware/auth-info-checker');
17
18 4
const commonApiRouter = require('./router/common-api-router');
19 4
const statusApiRouter = require('./router/status-api-router');
20 4
const statusTypeApiRouter = require('./router/status-type-api-router');
21 4
const deviceTypeApiRouter = require('./router/device-type-api-router');
22 4
const baseRouter = require('./router/ui-router');
23 4
const User = require('./repository/User');
24 4
const DeviceType = require('./repository/DeviceType');
25 4
const StatusType = require('./repository/StatusType');
26
27 4
const config = require('./config/server.config');
28 4
const NotifierError = require('./common/Error');
29
30 4
const util = require('./common/common-util');
31 4
const logger = require('winston');
32
33
// For JSX transpiling
34 4
require('babel-register');
35 4
require('babel-polyfill');
36
37 4
const server = new Hapi.Server();
38 4
server.connection({ port: process.env.PORT || config.defaults.port });
39
40 4
server.state('token', {
41
  ttl: config.auth.tokenTTL,
42
  isSecure: process.env.USE_HTTPS && process.env.USE_HTTPS === 'true',
43
  path: '/',
44
});
45
46 4
const plugins = [
47
  { register: vision },
48
  { register: inert },
49
  { register: HapiAuthJwt2 },
50
  { register: HapiErrorHandler, options: { apiPrefix: config.url.apiPrefix, errorView: 'Error' } },
51
  { register: HapiAuthChecker,
52
    options: {
53
      excludeUrlPatterns: [new RegExp(`^${config.url.apiPrefix}`), new RegExp('^/logout')],
54
    },
55
  },
56
  { register: HapiTransformer, options: { apiPrefix: config.url.apiPrefix } },
57
];
58
59 4
const _setAuthStrategy = () => {
60 4
  server.auth.strategy('jwt', 'jwt', {
61
    key: process.env.SECRET_KEY || config.auth.secretKey,
62
    validateFunc: (decoded, request, callback) => {
63
      // Check token IP address
64
      const clientIP = util.getClientIp(request);
65
      if (clientIP !== decoded.ip) {
66
        logger.warn(`[Auth] This client IP is matched with token info.: decoded.ip => ${decoded.ip}, client IP => ${clientIP}`);
67
        return callback(new NotifierError(NotifierError.Types.AUTH_TOKEN_INVALID), false);
68
      }
69
      // Check token expiration
70
      if (decoded.exp < new Date().getTime()) {
71
        logger.warn(`[Auth] This auth token is expired.: decoded.exp => ${decoded.exp}, now => ${new Date().getTime()}`);
72
        return callback(new NotifierError(NotifierError.Types.AUTH_TOKEN_EXPIRED), false);
73
      }
74
      return User.find({ username: decoded.username })
75
        .then((accounts) => {
76
          if (!accounts || accounts.length === 0) {
77
            logger.warn(`[Auth] This account is not exist.: ${decoded.username}`);
78
            return callback(new NotifierError(NotifierError.Types.AUTH_USER_NOT_EXIST, { username: decoded.username }), false);
79
          }
80
          return callback(null, true, accounts[0]);
81
        })
82
        .catch((e) => {
83
          logger.error(`[DB] DB error occurred: ${e.message}`);
84
          callback(new NotifierError(NotifierError.Types.DB), false);
85
        });
86
    },
87
    verifyOptions: { algorithms: ['HS256'] },
88
  });
89
90 4
  server.auth.default('jwt');
91
};
92
93 4
const _setViewEngine = () => {
94 4
  server.views({
95
    engines: { jsx: HapiReactViews },
96
    relativeTo: __dirname,
97
    path: config.directory.component,
98
  });
99
};
100
101 4
const _setRoutes = (extraRoutes) => {
102
  // for static assets
103 4
  server.route({
104
    method: 'GET',
105
    path: `${config.url.publicPrefix}/{param*}`,
106
    handler: {
107
      directory: {
108
        path: config.directory.public,
109
        listing: false,
110
      },
111
    },
112
    config: {
113
      auth: false,
114
    },
115
  });
116 4
  server.route(commonApiRouter);
117 4
  server.route(statusApiRouter);
118 4
  server.route(statusTypeApiRouter);
119 4
  server.route(deviceTypeApiRouter);
120 4
  server.route(baseRouter);
121 4
  if (extraRoutes) {
122
    server.route(extraRoutes);
123
  }
124
};
125
126 4
const _setInitalData = () => {
127 4
  let promises = [];
128 4
  return Promise.all([User.count(), DeviceType.count(), StatusType.count()])
129
    .then(([userCount, deviceTypeCount, statusTypeCount]) => {
130 4
      if (userCount === 0) {
131 1
        promises = promises.concat(config.initialData.users.map(user => User.add(user)));
132
      }
133 4
      if (deviceTypeCount === 0) {
134 4
        promises = promises.concat(config.initialData.deviceTypes.map(dt => DeviceType.add(dt)));
135
      }
136 4
      if (statusTypeCount === 0) {
137 2
        promises = promises.concat(config.initialData.statusTypes.map(user => StatusType.add(user)));
138
      }
139
    })
140 4
    .then(() => Promise.all(promises))
141 4
    .then(result => logger.log('[SET INITIAL DATA] success: ', result));
142
};
143
144 4
exports.addPlugin = (pluginSetting) => {
145
  plugins.push(pluginSetting);
146
};
147
148 4
exports.start = extraRoutes => server.register(plugins)
149
    .then(() => {
150 4
      _setAuthStrategy();
151 4
      _setViewEngine();
152 4
      _setRoutes(extraRoutes);
153
    })
154 4
    .then(() => _setInitalData())
155 4
    .then(() => server.start())
156
    .then(() => {
157 4
      logger.log('Server running at:', server.info.uri);
158 4
      return server;
159
    })
160
    .catch((error) => { throw error; });
161